
#pragma once

#include <ttg/all.h>

template <class T>
class TesterThread :public ttg::threads::Thread
{
	private:
		T *ev1;			//waits
		T *ev2;			//wakes another thread.
		T *on_finish;	//wakes main thread.
		bool is_first;
		size_t iteration_count;
	protected:
		virtual void work()
		{
			if (!is_first)
				ev1->wait();
			for (size_t i = 0; i < iteration_count; i++)
			{
				ev2->rise();
				ev1->wait();
			}
			if (is_first)
			{
				ev2->rise();
				on_finish->rise();
			}
			sleepDeep();						//fix me.
		}
	public:
		TesterThread(T *ev1, T *ev2, T *on_finish,
					 bool is_first, size_t iteration_count)
			:ttg::threads::Thread(true)
		{
			this->ev1 = ev1;
			this->ev2 = ev2;
			this->on_finish = on_finish;
			this->is_first = is_first;
			this->iteration_count = iteration_count;
		}
};

class ThreadEventTests
{
	private:
		//Returns average overhead in milliseconds.
		template <class T>
		static double testOverhead(size_t iteration_count)
		{
			T ev1;
			T ev2;
			T on_finish;
			double t_start = ttg::services::Timer::getRef()->getMilliSeconds();
			TesterThread<T> *t1 = new TesterThread<T>(&ev1, &ev2, &on_finish, true, iteration_count);
			TesterThread<T> *t2 = new TesterThread<T>(&ev2, &ev1, &on_finish, false, iteration_count);
			on_finish.wait();
			double t_end = ttg::services::Timer::getRef()->getMilliSeconds();
			ttg::threads::CurrentThread::sleep(0.5);
			return (t_end - t_start) / iteration_count;
		}
	public:
		static void test(ttg_internal::utils::PerfLogger ^logger)
		{
			logger->AddTest("ThreadEvents", "Measures overhead of thread events");
			ttg_internal::utils::PerfTable ^table = 
				logger->AddTable("Twothreads", "Two threads wakes each other",
								 gcnew array<System::String ^> {"Win32 FastEvent", "Win32 SlowEvent"},
								 gcnew array<System::String ^> {"1000", "6000", "11000", "16000"});
			for (size_t i = 0; i < 4; i++)
			{
				table->AddValue(0, i, System::String::Format(
						"{0} ms", testOverhead<ttg::threads::win32::Win32FastEvent>(1000 + 5000 * i)));
				table->AddValue(1, i, System::String::Format(
						"{0} ms", testOverhead<ttg::threads::win32::Win32SlowEvent>(1000 + 5000 * i)));
			}
		}
};
